package com.gitee.wsl.ext.number

import com.gitee.wsl.struct.version.Patterns
import kotlin.math.pow


/**
 * Formats this number to a string with the specified number of decimal places and rounding mode.
 *
 * @param places the number of decimal places.
 * @param roundingMode the rounding mode to apply.
 * @return the formatted string representation of this number.
 */
fun Number.format(
    places: Int,
    roundingMode: RoundingMode = RoundingMode.HALF_UP
): String {

    return toDouble()
        .round(places, roundingMode)
        .toString()
        .replace(Patterns.REMOVE_TRAILING_COMA, "")
}

 val NUMBER_UNITS: Array<String> = arrayOf(
    "K",
    "M",
    "B",
    "T",
    "Qa",
    "Qi",
    "Sx",
    "Sp",
    "Oc",
    "No",
    "Dc",
    "Ud",
    "Dd",
    "Td",
    "Qad",
    "Qid",
    "Sxd",
    "Spd",
    "Ocd",
    "Nod",
    "Vg",
    "Uvg",
    "Dvg",
    "Tvg",
    "Qavg",
    "Qivg",
    "Sxvg",
    "Spvg",
    "Ocvg",
    "Novg",
    "Tg",
    "Utg",
    "Dtg",
    "Ttg",
    "Qatg",
    "Qitg",
    "Sxtg",
    "Sptg",
    "Octg",
    "Notg",
    "Qaa",
    "Uqaa",
    "Dqaa",
    "Tqaa",
    "Qaqaa",
    "Qiqaa",
    "Sxqaa",
    "Spqaa",
    "Ocqaa",
    "Noqaa",
    "Qia",
    "Uqia",
    "Dqia",
    "Tqia",
    "Qaqia",
    "Qiqia",
    "Sxqia",
    "Spqia",
    "Ocqia",
    "Noqia",
    "Sx",
    "U",
    "D",
    "T",
    "Qa",
    "Qi",
    "Sx",
    "Sp",
    "Oc",
    "No",
    "Dc",
    "Ud",
    "Dd",
    "Td",
    "Qad",
    "Qid",
    "Sxd",
    "Spd",
    "Ocd",
    "Nod",
    "Vg",
    "Uvg",
    "Dvg",
    "Tvg",
    "Qavg",
    "Qivg",
    "Sxvg",
    "Spvg",
    "Ocvg",
    "Novg",
    "Tg",
    "Utg",
    "Dtg",
    "Ttg",
    "Qatg",
    "Qitg",
    "Sxtg",
    "Sptg",
    "Octg",
    "Notg",
    "Qaa",
    "Uqaa",
    "Dqaa",
    "Tqaa",
    "Qaqaa",
    "Qiqaa",
    "Sxqaa",
    "Spqaa",
    "Ocqaa",
    "Noqaa",
    "Qia",
    "Uqia",
    "Dqia",
    "Tqia",
    "Qaqia",
    "Qiqia",
    "Sxqia",
    "Spqia",
    "Ocqia",
    "Noqia"
)


/**
 * Converts this number to a human-readable string with units.
 *
 * @param rounding the number of decimal places.
 * @param roundingMode the rounding mode to apply.
 * @param formatSymbols the decimal format symbols to use.
 * @param units the array of units to use.
 * @return the human-readable string representation of this number with units.
 */
fun Number.toBeautifulString(
    rounding: Int = 2,
    roundingMode: RoundingMode = RoundingMode.HALF_UP,
    units: Array<String> = NUMBER_UNITS,
): String {
    var number = this.toDouble()
    var index = -1

    while (number >= 1000) {
        number /= 1000
        index++
    }

    return number.format(rounding, roundingMode) + (units.getOrNull(index) ?: "")
}

/**
 * Converts a human-readable string with units back to a double value.
 *
 * @param string the human-readable string with units.
 * @param units the array of units to use.
 * @return the double value represented by the string.
 */
fun fromBeautifulString(string: String, units: Array<String> = NUMBER_UNITS): Double {
    val number = string.replace(Patterns.NOT_DIGITS, "").toDouble()
    val unit = string.replace(Patterns.DIGITS, "")

    val index = units.indexOf(unit.uppercase())
    if (index == -1) return number

    return (number * 1000).pow(index + 1)
}